﻿
//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////

#include "GRepProbe.h"
#include "IUiView.h"
#include "IElement.h"
#include "IDocument.h"
#include "ElementId.h"
#include "IUiDocument.h"
#include "IDirectShape.h"
#include "IGraphicsNode.h"
#include "UiCommonDialog.h"
#include "IGenericElement.h"
#include "GcmpCommandState.h"
#include "IUserTransaction.h"
#include "GraphicsNodeUtils.h"
#include "CommandParameters.h"
#include "IElementModelShape.h"
#include "IPureGraphicsElement.h"
#include "IGraphicsElementShape.h"
#include "IUiDocumentViewManager.h"
#include "IGraphicsNodePathCollector.h"
#include "IElementViewSpecificShapeComponent.h"

#include <unordered_set>
#include "GrepProbeDlg.h"
#include "GNodeUtility.h"
#include "ObjectBrowser.h"
#include "GNodeWrapper.h"
#include "IDocumentManager.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 

using namespace gcmp;
using namespace Sample;

OwnerPtr<GRepProbe> GRepProbe::m_opGRepProbe = NEW_AS_OWNER_PTR(GRepProbe);

GRepProbe::GRepProbe()
    : m_isViewSpecific(false),
    m_isDirectShape(false), m_isPGE(false)
{
}

// 入口函数，同时用于CmdGRepProbe和CmdViewGRepProbe
void GRepProbe::Execute(bool isViewSpecific, IDocument* pDoc, ElementId elemId)
{
    // CmdViewGRepProbe会传入isViewSpecific为true
    m_isViewSpecific = isViewSpecific;

    m_isDirectShape = false;
    m_isPGE = false;

    IElement* pElement = pDoc->GetElement(elemId);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空", L"GDMP", L"2024-03-30");
    // 
    if (IGenericElement* pGenericElem = quick_cast<IGenericElement>(pElement))
    {
        IDirectShape* pDirectShape = quick_cast<IDirectShape>(pGenericElem->GetExternalObject());
        m_isDirectShape = (pDirectShape != nullptr);
    }
    else if (IPureGraphicsElement* pPGE = quick_cast<IPureGraphicsElement>(pElement))
    {
        m_isPGE = true;
    }
    //else：GRep浏览器中为只读

    UpdateUI(pDoc, elemId);
}

const bool Sample::GRepProbe::IsValid() const
{
    if (!m_cached_docId.IsValid() || m_cached_id.IsValid())
    {
        return false;
    }
    IDocumentManager* pDocMgr = IDocumentManager::Get();
    if (IDocument* pDoc = pDocMgr->GetDocument(m_cached_docId))
    {
        if (pDoc->GetElement(m_cached_id))
        {
            return true;
        }
    }
    return false;
}

void Sample::GRepProbe::UpdateGraphicsNodeToElement(IGraphicsNode_Wrapper * gNode_Wrapper)
{
    if (!gNode_Wrapper->GetElementId().IsValid()) { return; }
    if (m_cached_id != gNode_Wrapper->GetElementId()) { return; }

    IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDocViewMgr, L"获取UI文档视图管理器失败", L"GDMP", L"2024-03-30");
    IUiDocument* pUiDoc = pUiDocViewMgr->GetCurrentUiDocument();
    if (pUiDoc == nullptr) { return; }
    IDocument* pDoc = pUiDoc->GetDbDocument();
    if (pDoc == nullptr || pDoc->GetRuntimeId() != m_cached_docId) { return; }

    GrepProbeDlg* pGrepProbeDlg = GrepProbeDlg::GetOrCreate();
    IGraphicsNode_Wrapper* pGNode_Wrapper = pGrepProbeDlg->GetDisplayData();
    pGNode_Wrapper->RunSetFieldFuncs();

    OwnerPtr<IGraphicsElementShape> opCachedGRep = pGNode_Wrapper->GetCachedGRep();
    if (!opCachedGRep) { return; }
    IElement* pElem = pDoc->GetElement(gNode_Wrapper->GetElementId());
    if (!pElem)
    {
        // 图元获取不到，可能图元已经被删除。清理GRep探针浏览器
        pGrepProbeDlg->SetDisplayData(nullptr);
        return;
    };

    // 图形表达探针树中对应的目标图元可能移动过，下面代码根据缓存的GRep和最新GRep的包围盒，将缓存GRep移动到最新位置
    // IDirectShape和IPureGraphicsElement图元没有图元的位置信息，图元的旋转移动都是直接修改GRep。因此只能处理移动，无法处理旋转。
    {
        const IElementModelShape* pTargetLatestModelShape = pElem->GetElementModelShape();
        const IGraphicsElementShape* pTargetLatestGRep = pTargetLatestModelShape->GetGraphicsElementShape();
        Box3d targetLatestGRepBox = GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, pTargetLatestGRep);
        Box3d cachedTargetGRepBox = GraphicsNodeUtils::CalculateGraphicsNodeBoundingBox(pDoc, opCachedGRep.get());

        Vector3d movedVector = (targetLatestGRepBox.GetCenter() - cachedTargetGRepBox.GetCenter());
        Matrix4d matrix;
        matrix.MakeTranslate(movedVector);
        opCachedGRep->Transform(matrix);
    }

    // 开启事务，对IDirectShape或IPureGraphicsElement更新修改的GRep
    OwnerPtr<IUserTransaction> opTransaction = IUserTransaction::Create(pDoc, L"更新GNode到构件");
    DBG_WARN_AND_RETURN_VOID_UNLESS(opTransaction, L"opTransaction为空", L"GDMP", L"2024-03-30");

    if (m_isDirectShape)
    {
        IGenericElement* pGenericElement = quick_cast<IGenericElement>(pElem);
        if (pGenericElement == nullptr) { return; }

        IDirectShape* pDirectShape = quick_cast<IDirectShape>(pGenericElement->GetExternalObject());
        if (nullptr == pDirectShape) { return; }

        pDirectShape->SetGraphicsElementShape(TransferOwnership(opCachedGRep));
    }
    else if (m_isPGE)
    {
        IPureGraphicsElement* pPGE = quick_cast<IPureGraphicsElement>(pDoc->GetElement(m_cached_id));
        IElementModelShape* pElemModelShape = pPGE->GetElementModelShape();
        pElemModelShape->SetGraphicsElementShape(TransferOwnership(opCachedGRep));
    }

    opTransaction->Commit();

    UpdateUI(pDoc, m_cached_id);
}

void Sample::GRepProbe::UpdateUI(IDocument* pDoc, ElementId id)
{
    // 只有IDirectShape或IPureGraphicsElement可以修改，视图GRep也是只读
    bool isReadOnly = ((!m_isDirectShape) && (!m_isPGE)) || (m_isViewSpecific);
    IElement* pElement = pDoc->GetElement(id);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"pElement为空", L"GDMP", L"2024-03-30");
    OwnerPtr<IGraphicsElementShape> opGRep = nullptr;

    if (m_isViewSpecific) // 获得视图GRep，例如尺寸的GRep是视图GRep
    {
        const IElementViewSpecificShapeComponent* pViewShapeComponent = pElement->GetViewSpecificShapeComponent();
        if (pViewShapeComponent == nullptr)
        {
            UiCommonDialog::ShowMessageBox(L"提示", L"选择图元的IElementViewSpecificShapeComponent为空，因此探针无效。", (int)UiCommonDialog::ButtonType::Yes);
            return;
        }
        IUiDocumentViewManager* pUiDocViewMgr = IUiDocumentViewManager::Get();
        IUiView* pUiView = pUiDocViewMgr->GetCurrentUiView();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pUiView, L"pUiView为空", L"GDMP", L"2024-03-30");
        IModelView* pModelView = pUiView->GetModelView();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pModelView, L"pModelView为空", L"GDMP", L"2024-03-30");
        opGRep = pViewShapeComponent->CreateViewSpecificElementShape(pModelView);
        if (opGRep == nullptr)
        {
            UiCommonDialog::ShowMessageBox(L"提示", L"选择的视图图形表达中IGraphicsElementShape为空，因此探针无效。", (int)UiCommonDialog::ButtonType::Yes);
            return;
        }
    }
    else // 获得模型GRep
    {
        IElementModelShape* pElementModelShape = pElement->GetElementModelShape();
        if (pElementModelShape == nullptr)
        {
            UiCommonDialog::ShowMessageBox(L"提示", L"选择的模型图形表达中IElementModelShape为空，因此探针无效。", (int)UiCommonDialog::ButtonType::Yes);
            return;
        }
        const IGraphicsElementShape* pSourceGRep = pElementModelShape->GetGraphicsElementShape();
        if (pSourceGRep == nullptr)
        {
            UiCommonDialog::ShowMessageBox(L"提示", L"选择的模型图形表达中IGraphicsElementShape为空，因此探针无效。", (int)UiCommonDialog::ButtonType::Yes);
            return;
        }
        opGRep = IGraphicsElementShape::Create(pSourceGRep);
        if (opGRep == nullptr)
        {
            UiCommonDialog::ShowMessageBox(L"提示", L"选择的模型图形表达中IGraphicsElementShape为空，因此探针无效。", (int)UiCommonDialog::ButtonType::Yes);
            return;
        }
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(opGRep, L"opGRep为空", L"GDMP", L"2024-03-30");

    // 清空GRep浏览器
    ObjectBrowser* pObjectBrowser = ObjectBrowser::GetOrCreate();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pObjectBrowser, L"pObjectBrowser为空", L"GDMP", L"2024-03-30");
    pObjectBrowser->SetDataAndUpdate(nullptr);
    pObjectBrowser->SetOnApplyCallBack(ObjectBrowser::CreateOnApplyCallBack(&GRepProbe::UpdateGraphicsNodeToElement, this));

    // 更新GRep探针浏览器
    GrepProbeDlg* pGrepProbeDlg = GrepProbeDlg::GetOrCreate();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGrepProbeDlg, L"pGrepProbeDlg为空", L"GDMP", L"2024-03-30");
    pGrepProbeDlg->ShowDock();

    // 更新GRep浏览器
    OwnerPtr<IGraphicsNode_Wrapper> opGNodeWrapper = GNodeUtility::CreateGNodeWrapperTree(pDoc, id, opGRep.get(), opGRep.get(), isReadOnly, nullptr);
    DBG_WARN_AND_RETURN_VOID_UNLESS(opGNodeWrapper, L"opGNodeWrapper为空", L"GDMP", L"2024-03-30");
    pGrepProbeDlg->SetDisplayData(TransferOwnership(opGNodeWrapper));
    pGrepProbeDlg->GetDisplayData()->CacheGRep(TransferOwnership(opGRep));

    m_cached_id = id;
    m_cached_docId = pDoc->GetRuntimeId();

}

